package logic

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/apache/rocketmq-client-go/v2"
	"github.com/apache/rocketmq-client-go/v2/primitive"
	"github.com/apache/rocketmq-client-go/v2/producer"
	uuid "github.com/satori/go.uuid"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"order_srv/global"
	"order_srv/goods_proto"
	"order_srv/inventory_proto"
	"order_srv/model"
	"order_srv/order_proto"
	"os"
	"strconv"
	"time"
)

type OrderListener struct {
	Code       codes.Code
	Detail     string
	ID         int32
	OrderMount float32
	Ctx        context.Context
}

// ExecuteLocalTransaction 是一个函数，它属于 DemoListener 结构体
func (dl *OrderListener) ExecuteLocalTransaction(msg *primitive.Message) primitive.LocalTransactionState {
	orderData := model.OrderInfo{}
	json.Unmarshal(msg.Body, &orderData)
	var shoppingCart []model.ShoppingCart
	goodsNumsMap := make(map[int32]int32)
	//查询购物车商品是否存在
	res := global.DB.Where(&model.ShoppingCart{UserId: orderData.UserId, Checked: true}).Find(&shoppingCart)
	//判断购物车是否存在
	if res.RowsAffected == 0 {
		zap.S().Error("购物车不存在")
		return primitive.CommitMessageState
	}
	//获取商品ID
	var goodsIDs []int32
	//获取商品数量
	for _, cart := range shoppingCart {
		goodsIDs = append(goodsIDs, int32(cart.GoodsId))
		goodsNumsMap[int32(cart.GoodsId)] = cart.Nums
	}
	//调用商品微服务
	goods, err := global.GoodsSrvConnect.BatchGetGoods(context.Background(), &goods_proto.BatchGoodsIdInfo{Id: goodsIDs})
	if err != nil {
		zap.S().Error("查询商品详情失败")
		return primitive.CommitMessageState
	}
	//订单总金额
	var orderMount float32
	// 商品库存详情
	var goodsInvInfo []*inventory_proto.GoodsInvInfo
	//订单商品
	var orderGoods []*model.OrderGoods
	//循环商品信息
	for _, v := range goods.Data {
		orderMount += v.ShopPrice * float32(goodsNumsMap[v.Id])
		orderGoods = append(orderGoods, &model.OrderGoods{
			GoodsId:    int(v.Id),
			GoodsName:  v.Name,
			GoodsImage: v.GoodsFrontImage,
			GoodsPrice: v.ShopPrice,
			Nums:       int(goodsNumsMap[v.Id]),
		})
		goodsInvInfo = append(goodsInvInfo, &inventory_proto.GoodsInvInfo{
			GoodsID: v.Id,
			Nums:    goodsNumsMap[v.Id],
		})
	}

	//调用库存微服务 扣减库存
	_, err = global.InventorySrvConnect.Sell(context.Background(), &inventory_proto.SellInfo{
		GoodsInfo: goodsInvInfo,
		OrderSn:   orderData.OrderSn,
	})
	if err != nil {
		zap.S().Error("扣减库存失败")
		return primitive.CommitMessageState
	}
	tx := global.DB.Begin()
	orderInfo := model.OrderInfo{
		UserId:       orderData.UserId,
		OrderSn:      orderData.OrderSn,
		Status:       "PAYING",
		OrderMount:   orderMount,
		Address:      orderData.Address,
		SingerName:   orderData.SingerName,
		SingerMobile: orderData.SingerMobile,
		Post:         orderData.Post,
		PayTime:      time.Now(),
	}
	if result := tx.Create(&orderInfo); result.RowsAffected == 0 {
		tx.Rollback()
		zap.S().Error("创建订单失败")
		return primitive.CommitMessageState
	}
	dl.ID = orderInfo.ID
	dl.OrderMount = orderInfo.OrderMount
	//循环赋值订单商品中的orderID
	for k, _ := range orderGoods {
		orderGoods[k].OrderId = int(orderInfo.ID)
	}
	//批量插入
	if result := tx.CreateInBatches(orderGoods, 100); result.RowsAffected == 0 {
		tx.Rollback()
		zap.S().Error("创建订单商品失败")
		return primitive.CommitMessageState

	}
	//从购物车中删除已购买的记录
	if result := tx.Where(&model.ShoppingCart{UserId: orderData.UserId, Checked: true}).Delete(&shoppingCart); result.RowsAffected == 0 {
		tx.Rollback()
		zap.S().Error("删除购物车商品失败")
		return primitive.CommitMessageState
	}
	tx.Commit()
	return primitive.RollbackMessageState
}

func (dl *OrderListener) CheckLocalTransaction(msg *primitive.MessageExt) primitive.LocalTransactionState {
	orderData := model.OrderInfo{}
	json.Unmarshal(msg.Body, &orderData)
	tx := global.DB.Where(&model.OrderInfo{OrderSn: orderData.OrderSn}).Find(&model.OrderInfo{})
	if tx.RowsAffected == 0 {
		return primitive.CommitMessageState
	}
	return primitive.RollbackMessageState
}
func (s *Server) Create(ctx context.Context, in *order_proto.OrderRequest) (*order_proto.OrderInfoResponse, error) {
	// 生成唯一的订单编号
	orderSn := fmt.Sprintf("%s", uuid.NewV4())
	// 创建订单的基本信息
	orderInfo := model.OrderInfo{
		UserId:       int(in.UserId),
		OrderSn:      orderSn,
		Status:       "PAYING",
		Address:      in.Address,
		SingerName:   in.Name,
		SingerMobile: in.Mobile,
		Post:         in.Post,
		PayTime:      time.Now(),
	}
	// 将订单信息序列化为 JSON 格式
	marshal, _ := json.Marshal(orderInfo)
	orderListener := OrderListener{Ctx: ctx}
	producerGroup := "producerGroup" + uuid.NewV4().String()
	// 创建一个新的事务性消息生产者
	p, _ := rocketmq.NewTransactionProducer(
		// 创建一个新的 DemoListener 实例，用于处理事务消息
		&orderListener,
		// 创建一个新的 Passthrough 解析器实例，并指定 NameServer 的地址
		producer.WithNsResolver(primitive.NewPassthroughResolver([]string{fmt.Sprintf("%s:%d", global.ServerConfig.RocketMqConfig.Host, global.ServerConfig.RocketMqConfig.Port)})),
		// 设置生产者的重试次数为 1
		producer.WithRetry(1),
		producer.WithGroupName(producerGroup),
	)
	// 启动生产者
	err := p.Start()
	// 处理可能发生的生产者启动错误
	if err != nil {
		zap.S().Error("启动生产者失败")
		// 退出程序，非零状态码 1 表示程序遇到错误
		os.Exit(1)
	}

	// 发送事务消息到指定的 Topic
	_, err = p.SendMessageInTransaction(context.Background(),
		// 创建一个新的 Message 实例，指定 Topic 为 TopicTest5，并设置消息体为序列化后的订单信息
		primitive.NewMessage(global.ServerConfig.RocketMqConfig.Topic, marshal))
	if err != nil {
		zap.S().Error("发送事务消息失败")
	}
	return &order_proto.OrderInfoResponse{
		Id:      orderListener.ID,
		UserId:  int32(orderInfo.UserId),
		OrderSn: orderInfo.OrderSn,
		PayType: strconv.Itoa(int(orderInfo.PayType)),
		Status:  orderInfo.Status,
		Post:    orderInfo.Post,
		Total:   orderListener.OrderMount,
		Address: orderInfo.Address,
		Name:    orderInfo.SingerName,
		Mobile:  orderInfo.SingerMobile,
	}, nil
}
